In this notebook, we will:
Import all needed packages, and create PlateReconstruction and Plot objects for the Muller et al. (2019) plate tectonic model.
import os
import cartopy.crs as ccrs
import gplately
import matplotlib.pyplot as plt
import numpy as np
Using GPlately's download module, we can easily download a variety of plate tectonic models!
gdownload = gplately.download.DataServer("Muller2019")
rotation_model, topology_features, static_polygons = gdownload.get_plate_reconstruction_files()
coastlines, continents, COBs = gdownload.get_topology_geometries()
time = 0 # Ma
model = gplately.PlateReconstruction(rotation_model, topology_features, static_polygons)
gplot = gplately.PlotTopologies(model, time, coastlines, continents, COBs)
Checking whether the requested files need to be updated... Requested files are up-to-date! Checking whether the requested files need to be updated... Requested files are up-to-date!
DataServer for rasters¶Let's use GPlately's DataServer object to download Muller et al. 2019 netCDF age grids.
There is a unique age grid for each millionth year - let's access the 0 Ma age grid by passing time to get_age_grid. It is returned as a masked array.
time = 0 # Ma
muller_2019_age_grid = gdownload.get_age_grid(time)
Checking whether the requested files need to be updated... Requested files are up-to-date!
graster = gplately.Raster(
muller_2019_age_grid,
model,
extent=[-180, 180, -90, 90],
)
fig = plt.figure(figsize=(16, 12))
plt.imshow(graster.data, origin="lower", cmap="YlGnBu")
plt.show()
Let's plot this netCDF grid along with coastlines, mid-ocean ridges and subduction zones (with teeth) resolved from the Muller et al. 2019 plate model.
fig = plt.figure(figsize=(16, 12))
ax1 = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude=20))
gplot.time = time
gplot.plot_grid(ax1, graster.data, cmap='YlGnBu', vmin=0, vmax=200)
gplot.plot_coastlines(ax1, edgecolor='k', facecolor='1', alpha=0.1)
gplot.plot_trenches(ax1, color='magenta', zorder=5)
gplot.plot_ridges(ax1, color='b', zorder=5)
gplot.plot_transforms(ax1, color='lightblue', linewidth=0.75)
gplot.plot_subduction_teeth(ax1, color='magenta')
ax1.set_title("{} Ma".format(time))
plt.show()
model = gplately.PlateReconstruction(rotation_model, topology_features, static_polygons)
muller_2019_age_grid = gdownload.get_age_grid(time)
graster = gplately.Raster(
plate_reconstruction=model,
data=muller_2019_age_grid,
extent=[-180, 180, -90, 90],
)
# Set grid size in x and y directions
graster.resize(20, 10, overwrite=True)
# Plot resampled and resized age grid
fig = plt.figure(figsize=(16,12))
ax1 = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude = 20))
gplot.plot_grid(ax1, graster.data, cmap='YlGnBu', vmin=0, vmax=200)
gplot.plot_coastlines(ax1, edgecolor='k', facecolor='1', alpha=0.1)
gplot.plot_trenches(ax1, color='magenta', zorder=5)
gplot.plot_ridges(ax1, color='b', zorder=5)
gplot.plot_subduction_teeth(ax1, color='magenta')
ax1.set_title("{} Ma".format(time))
plt.show()
Checking whether the requested files need to be updated... Requested files are up-to-date!
Let's visualise an ETOPO1 relief raster. GPlately also makes it easy to import, using get_raster
Alternatively, you can import a local netcdf file using gplately.grids.read_netcdf_grid
etopo = gdownload.get_raster("ETOPO1_tif")
print(np.shape(etopo))
print(np.size(etopo) // 3)
Checking whether the requested files need to be updated... Requested files are up-to-date! (2700, 5400, 3) 14580000
etopo is a large (5400 x 2700 pixels) RGB image, with a total of 14,580,000 grid points. We can visualise it using a number of methods, including Raster.imshow.
raster = gplately.Raster(data=etopo, origin="upper")
fig = plt.figure(figsize=(16, 12))
ax1 = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude=20))
raster.imshow(ax=ax1, interpolation="none")
plt.show()
We can also resize this RGB raster using the Raster.resize and Raster.resample methods. Here we resample it to a $2\degree \times 2\degree$ resolution, then plot it using Raster.imshow.
etopo_downscaled = gplately.Raster(
data=raster.resample(2, 2),
origin="upper",
)
etopo_downscaled.imshow(projection=ccrs.Robinson(central_longitude=180), interpolation="none")
<matplotlib.image.AxesImage at 0x1b2aeed90>
The ETOPO1 raster can be reconstructed back in time using the Raster and PlateReconstruction classes.
First we create our Raster object, where we can specify our plate model we want to reconstruct with.
After this, we use reconstruct to reconstruct the raster to a given time.
graster = gplately.Raster(
plate_reconstruction=model,
data=etopo,
extent="global", # equivalent to (-180, 180, -90, 90)
origin="upper", # or set extent to (-180, 180, 90, -90)
)
white_rgb = (255, 255, 255) # RGB code for white, to fill gaps in output
rgb = graster.reconstruct(50, threads=4, fill_value=white_rgb, return_array=True)
fig = plt.figure(figsize=(16, 12))
ax1 = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude=180))
gplot.plot_grid(ax1, rgb, origin="upper")
<matplotlib.image.AxesImage at 0x1b2ae8d90>
Rasters can be reconstructed in-place (inplace=True), and fill_value can be set to any valid matplotlib colour when reconstructing RGB images.
etopo_flipped = np.flipud(etopo)
raster = gplately.Raster(
plate_reconstruction=model,
data=etopo_flipped,
extent="global",
origin="lower",
)
raster.reconstruct(time=75, threads=4, fill_value="darkblue", inplace=True)
raster.imshow(projection=ccrs.Robinson())
<matplotlib.image.AxesImage at 0x1b2aa64d0>
By default, [Raster.reconstruct](reconstruct uses self.plate_reconstruction.static_polygons to assign plate IDs to grid points. To override this behaviour, pass any collection of pygplates.Feature (e.g. list, pygplates.FeatureCollection, etc) to the partitioning_features argument.
raster = gplately.Raster(
plate_reconstruction=model,
data=etopo,
extent="global",
origin="upper",
)
raster.reconstruct(140, partitioning_features=continents, threads=4, fill_value="grey", inplace=True)
raster.imshow(projection=ccrs.Orthographic(0, -80))
plt.gca().set_title("Reconstructed to 140 Ma")
Text(0.5, 1.0, 'Reconstructed to 140 Ma')
Rasters can be also be reverse reconstructed forward in time!
raster = gplately.Raster(
plate_reconstruction=model,
data=etopo,
time=0,
origin="upper",
)
reconstructed = raster.reconstruct(50, fill_value="white", threads=4)
reverse_reconstructed = reconstructed.reconstruct(0, fill_value="white", threads=4)
# plot
fig, axs = plt.subplots(3, 1, figsize=(8, 12), subplot_kw={"projection": ccrs.Mollweide(central_longitude=0)})
raster.imshow(ax=axs[0])
reconstructed.imshow(ax=axs[1])
reverse_reconstructed.imshow(ax=axs[2])
axs[0].set_title("Original image (present day)")
axs[1].set_title("Reconstructed to 50 Ma")
axs[2].set_title("Reverse reconstructed back to present day")
plt.show()
Similar to above, we can also reconstruct netcdf grids! GPlately also includes ETOPO1 as a netcdf for download.
etopo = gdownload.get_raster("ETOPO1_grd").astype("float")
graster = gplately.Raster(
plate_reconstruction=model,
data=etopo,
extent="global",
origin="lower", # note: here it is 'lower', while the ETOPO tiff uses 'upper'
)
reconstructed_etopo = graster.reconstruct(50, threads=4, return_array=True)
# plot
fig = plt.figure(figsize=(16, 12))
ax1 = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude=20))
gplot.plot_grid(ax1, reconstructed_etopo, origin="lower")
plt.show()
Checking whether the requested files need to be updated... Requested files are up-to-date!
The reconstructed netcdf can also be saved using gplately.grids.write_netcdf_grid
# Save the reconstructed ETOPO grid to netCDF
# (note: this ETOPO netCDF grid is high-res, ~190+MB)
save_filename = os.path.join(
"NotebookFiles",
"reconstructed_etopo.nc",
)
gplately.grids.write_netcdf_grid(save_filename, reconstructed_etopo)
As an example of linear interpolation, let's project points along trenches out a distance of 250 km and check which projected points lie inside a continental raster.
# Define the continental grid
continental_grid_filename = os.path.join(
"NotebookFiles",
"continental_grid_0.nc",
)
continental_raster = gplately.Raster(
continental_grid_filename,
model,
extent=[-180, 180, -90, 90],
)
# Extract subduction polarity angle, and the lat-lon coordinates of each trench point
trench_data = model.tesselate_subduction_zones(time, ignore_warnings=True)
trench_normal_azimuthal_angle = trench_data[:, 7]
trench_pt_lon = trench_data[:, 0]
trench_pt_lat = trench_data[:, 1]
# Project the 250km arc-trench distance onto an Earth sphere
arc_distance = 250 / (gplately.tools.geocentric_radius(trench_pt_lat) / 1e3)
# Lat and lon coordinates of all trench points after being projected out 250 km in the direction of subduction.
dlon = arc_distance * np.sin(np.radians(trench_normal_azimuthal_angle))
dlat = arc_distance * np.cos(np.radians(trench_normal_azimuthal_angle))
ilon = trench_pt_lon + np.degrees(dlon)
ilat = trench_pt_lat + np.degrees(dlat)
Let's use GPlately to linearly interpolate these projected trench points onto the continental grids using Raster.interpolate
# Use GPlately to interpolate these new points on the defined grid
sampled_points = continental_raster.interpolate(ilon, ilat, method='linear')
# sampled_point[0] is a list of points in the grid (ascribed the integer 1). Collect their indices.
in_raster_indices = sampled_points > 0
# Get the lat-lon coordinates of the in_raster points
lat_in = ilat[in_raster_indices]
lon_in = ilon[in_raster_indices]
Plot the in-raster points along with the raster, trenches, and coastlines.
fig = plt.figure(figsize=(16, 12), dpi=100)
ax1 = fig.add_subplot(111, projection=ccrs.Mollweide(central_longitude=20))
gplot.time = time
gplot.plot_grid_from_netCDF(ax1, continental_grid_filename, cmap="twilight", alpha=0.5, vmin=0, vmax=200)
gplot.plot_coastlines(ax1, edgecolor='k', facecolor='1', alpha=0.1)
gplot.plot_trenches(ax1, color='r', zorder=5)
# Plot the trench points in-continent
ax1.plot(
lon_in, lat_in,
linestyle="none",
marker="o",
markersize=0.25,
markerfacecolor="blue",
markeredgecolor="blue",
transform=ccrs.PlateCarree(),
)
plt.title("%i Ma" %time)
# Custom legend
from matplotlib.lines import Line2D
handles = [
Line2D([0], [0], color="red"),
Line2D([0], [0], color="blue"),
]
labels = [
"Trenches",
"Arc segments in continental grids",
]
plt.legend(handles, labels, loc="lower left")
plt.show()